package com.tianquan.miracle.proxy;

import com.tianquan.miracle.aop.JoinPintImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

/**
 * @Author: tianquan
 * @date: 2024-10-09  10:03
 * @Description: JDK动态代理类，用于处理方法调用
 */
public class JdkMethodInvocation implements InvocationHandler, MethodInvocation {

    /**
     * 需要代理的对象
     */
    private final Object object;

    /**
     * 需要代理的所有方法名称
     */
    private final List<String> objectMethodName;

    /**
     * 前置增强方法
     */
    private final Method beforeMethod;

    /**
     * 后置增强方法
     */
    private final Method afterMethod;

    /**
     * 用来调用对应方法的类
     */
    private final Object target;

    /**
     * 环绕增强方法
     */
    private final Method aroundMethod;

    /**
     * 构造函数，初始化代理对象所需的信息
     *
     * @param object           需要代理的对象
     * @param objectMethodName 需要代理的方法名称列表
     * @param beforeMethod     前置增强方法
     * @param aroundMethod     环绕增强方法
     * @param afterMethod      后置增强方法
     * @param target           目标对象，用于调用增强方法
     */
    public JdkMethodInvocation(Object object, List<String> objectMethodName, Method beforeMethod,
                               Method aroundMethod, Method afterMethod, Object target) {
        this.target = target;
        this.afterMethod = afterMethod;
        this.aroundMethod = aroundMethod;
        this.beforeMethod = beforeMethod;
        this.objectMethodName = objectMethodName;
        this.object = object;
    }

    /**
     * 当代理对象调用方法时，该方法会被调用
     *
     * @param proxy  代理对象
     * @param method 被调用的方法
     * @param args   方法参数
     * @return 方法执行结果
     * @throws Throwable 方法执行过程中可能抛出的异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 如果不是需要代理的方法，则直接调用
        if (!objectMethodName.contains(method.getName())) {
            return method.invoke(this.object, args);
        }
        Object invoke;
        // 调用前置增强方法
        if (beforeMethod != null) {
            invoke = beforeMethod.invoke(target);
        }
        // 是否有环绕通知
        if (aroundMethod != null) {
            // 调用环绕增强方法
            invoke = aroundMethod.invoke(target, new JoinPintImpl(this.object, method, args));
        } else {
            // 通过反射调用代理类的方法
            invoke = method.invoke(this.object, args);
        }
        // 调用后置增强方法
        if (afterMethod != null) {
            invoke = afterMethod.invoke(target);
        }
        return invoke;
    }

    /**
     * 获取代理对象
     *
     * @return 代理对象
     */
    @Override
    public Object getProxy() {
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                this);
    }

}

